﻿using System.Collections;
using System.Collections.Generic;
using Unity.Collections;
using Unity.Mathematics;
using UnityEngine;

public class BeizerUilityTools
{

    /// <summary>
    /// 转化斜率值
    /// </summary>
    /// <param name="dir"></param>
    /// <returns></returns>
    public static float VectorConversionToSlope(Vector3 dir)
    {
        return dir.z / dir.x;
    }

    /// <summary>
    /// 获取两点之间的贝塞尔曲线点
    /// </summary>
    /// <param name="startGradient"></param>
    /// <param name="endGradient"></param>
    /// <param name="startPoint"></param>
    /// <param name="endPoint"></param>
    /// <param name="middlePoint"></param>
    /// <returns></returns>
    public static Vector3 CaculateBeizerNodeByTwoLine(float startGradient, float endGradient, Vector3 startPoint, Vector3 endPoint, Vector3 middlePoint)
    {
        if (startGradient == endGradient)
        {
            Debug.LogError("斜率相等，无法计算贝赛点");
            return middlePoint;
        }
        float bezierX = (startGradient * startPoint.x - endGradient * endPoint.x - startPoint.z + endPoint.z) / (startGradient - endGradient);
        float beizerY = startGradient * (bezierX - startPoint.x) + startPoint.z;
        return new Vector3(bezierX, 0, beizerY);
    }

    /// <summary>
    /// 获取点之间的距离
    /// </summary>
    /// <param name="totalVector3"></param>
    /// <returns></returns>
    public static float GetTotalLength(Vector3[] totalVector3)
    {
        float totalLength = 0;
        for (int i = 1; i < totalVector3.Length; i++)
        {
            totalLength += (totalVector3[i] - totalVector3[i - 1]).magnitude;
        }
        return totalLength;
    }

    /// <summary>
    /// 获取点之间的距离
    /// </summary>
    /// <param name="totalVector3"></param>
    /// <returns></returns>
    public static float GetTotalLength(NativeArray<float3> totalVector3)
    {
        float totalLength = 0;
        for (int i = 1; i < totalVector3.Length; i++)
        {
            totalLength += math.length(totalVector3[i] - totalVector3[i - 1]);
        }
        return totalLength;
    }


    /// <summary>
    /// 获取点之间的距离
    /// </summary>
    /// <param name="totalVector3"></param>
    /// <returns></returns>
    public static float GetTotalLength(NativeArray<Vector3> totalVector3)
    {
        float totalLength = 0;
        for (int i = 1; i < totalVector3.Length; i++)
        {
            totalLength += (totalVector3[i] - totalVector3[i - 1]).magnitude;
        }
        return totalLength;
    }


    /// <summary>
    /// 获取点之间的距离
    /// </summary>
    /// <param name="totalVector3"></param>
    /// <returns></returns>
    public static float GetSqrTotalLength(Vector3[] totalVector3)
    {
        float totalLength = 0;
        for (int i = 1; i < totalVector3.Length; i++)
        {
            totalLength += CaculateSqrDistance(totalVector3[i], totalVector3[i - 1]);
        }
        return totalLength;
    }

    public static float CaculateSqrDistance(Vector3 start, Vector3 end)
    {
        float valueX = (start.x - end.x);
        float valutY = (start.y - end.y);
        float valutZ = (start.z - end.z);
        return valueX * valueX + valutY * valutY + valutZ * valutZ;
    }


    /// <summary>
    /// 获取别塞尔曲线的采样点
    /// </summary>
    /// <param name="startNode"></param>
    /// <param name="endNode"></param>
    /// <param name="bezierNode"></param>
    /// <param name="pointCount"></param>
    /// <returns></returns>
    public static float BezierLength(Vector3 startNode, Vector3 endNode, Vector3 bezierNode, int pointCount = 30)
    {
        if (pointCount < 2)
        {
            return 0;
        }
        float length = 0.0f;
        Vector3 lastPoint = BezierCurve(startNode, endNode, bezierNode, 0.0f / (float)pointCount);
        for (int i = 1; i <= pointCount; i++)
        {
            Vector3 point = BezierCurve(startNode, endNode, bezierNode, (float)i / (float)pointCount);
            length += Vector3.Distance(point, lastPoint);
            lastPoint = point;
        }
        return length;
    }

    /// <summary>
    /// 二次贝塞尔
    /// </summary>
    public static Vector3 BezierCurve(Vector3 startNode, Vector3 endNode, Vector3 bezierNode, float t)
    {
        return (1 - t) * (1 - t) * startNode + 2 * t * (1 - t) * bezierNode + t * t * endNode;
    }

    /// <summary>
    /// 二次贝塞尔
    /// </summary>
    public static float3 BezierCurve(float3 startNode, float3 endNode, float3 bezierNode, float t)
    {
        return (1 - t) * (1 - t) * startNode + 2 * t * (1 - t) * bezierNode + t * t * endNode;
    }

    /// <summary>
    /// 二次贝塞尔斜率
    /// </summary>
    /// <param name="startNode"></param>
    /// <param name="endNode"></param>
    /// <param name="bezierNode"></param>
    /// <param name="t"></param>
    /// <returns></returns>
    public static Vector3 BezierCurveGradient(Vector3 startNode, Vector3 endNode, Vector3 bezierNode, float t)
    {

        return (2 * startNode - 4 * bezierNode + 2 * endNode) * t + 2 * bezierNode - 2 * startNode;
    }

    /// <summary>
    /// 二次贝塞尔斜率
    /// </summary>
    /// <param name="startNode"></param>
    /// <param name="endNode"></param>
    /// <param name="bezierNode"></param>
    /// <param name="t"></param>
    /// <returns></returns>
    public static Vector3 BezierCurveGradient(float3 startNode, float3 endNode, float3 bezierNode, float t)
    {

        return (2 * startNode - 4 * bezierNode + 2 * endNode) * t + 2 * bezierNode - 2 * startNode;
    }

    /// <summary>
    /// 通过斜率得到贝赛尔曲线的位置
    /// </summary>
    /// <param name="startNode"></param>
    /// <param name="endNode"></param>
    /// <param name="t"></param>
    /// <returns></returns>
    public static Vector3 GetBezierCurePiontByGradient(Vector3 gradient, Vector3 startNode, Vector3 endNode, float t)
    {
        return (gradient + (1 - t) * 2 * startNode - 2 * endNode * t) / (2 * (1 - 2 * t));
    }

    /// <summary>
    /// 获取贝塞尔曲线交点的t值
    /// </summary>
    /// <param name="startNodeValue"></param>
    /// <param name="endNodeValue"></param>
    /// <param name="bezierNodeValue"></param>
    /// <param name="value"></param>
    /// <returns></returns>
    public static float GetBizerCurveTByValue(float startNodeValue, float endNodeValue, float bezierNodeValue, float value)
    {
        float t = 0;
        if ((startNodeValue + endNodeValue - 2 * bezierNodeValue) == 0)
        {
            t = (value - endNodeValue) / (2 * (bezierNodeValue - startNodeValue));
        }
        else
        {
            float t1 = (2 * (startNodeValue - bezierNodeValue) + Mathf.Sqrt((2 * bezierNodeValue - 2 * startNodeValue) * (2 * bezierNodeValue - 2 * startNodeValue) - 4 * (startNodeValue + endNodeValue - 2 * bezierNodeValue) * (startNodeValue - value))) / (2 * (startNodeValue + endNodeValue - 2 * bezierNodeValue));
            float t2 = (2 * (startNodeValue - bezierNodeValue) - Mathf.Sqrt((2 * bezierNodeValue - 2 * startNodeValue) * (2 * bezierNodeValue - 2 * startNodeValue) - 4 * (startNodeValue + endNodeValue - 2 * bezierNodeValue) * (startNodeValue - value))) / (2 * (startNodeValue + endNodeValue - 2 * bezierNodeValue));
            t = (t1 < 0 || t1 > 1) ? t2 : t1;
        }
        return t;
    }

}